package hr.ctg.web.servlet;

import static java.lang.Integer.parseInt;
import hr.ctg.domain.model.Slika;
import hr.ctg.service.dao.SlikaDAO;

import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.imageio.ImageIO;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.ImageIcon;

import org.jboss.seam.Component;
import org.jboss.seam.cache.CacheProvider;

/**
 * Serves images and other member content
 * 
 * @author Shane Bryzak
 */
public class ImageServlet extends HttpServlet {

	private static final long serialVersionUID = -8461940507242022217L;

	/**
	 * The maximum width allowed for image rescaling
	 */
	private static final int MAX_IMAGE_WIDTH = 800;

	private byte[] noImage;

	@Override
	public void init(final ServletConfig config) throws ServletException {
		final InputStream in = config.getServletContext().getResourceAsStream(
				"/theme/default/images/common/no_image.png");
		if (in != null) {
			final ByteArrayOutputStream out = new ByteArrayOutputStream();
			final byte[] buffer = new byte[512];
			try {
				int read = in.read(buffer);
				while (read != -1) {
					out.write(buffer, 0, read);
					read = in.read(buffer);
				}

				noImage = out.toByteArray();
			} catch (final IOException e) {
			}
		}

	}

	@Override
	protected void doGet(final HttpServletRequest req,
			final HttpServletResponse res) throws ServletException, IOException {
		final OutputStream outputStream = res.getOutputStream();
		try {
			final String idSlike = req.getParameter("idSlike");
			final String idObjekta = req.getParameter("idObjekta");
			final String idParka = req.getParameter("idParka");
			final String idMjesta = req.getParameter("idMjesta");
			final String idOtoka = req.getParameter("idOtoka");
			Slika slika = null;
			if (idSlike != null) {
				slika = getSlika(parseInt(idSlike));
			} else if (idObjekta != null) {
				slika = getSlikaByIdObjekta(parseInt(idObjekta));
			} else if (idMjesta != null) {
				slika = getSlikaByIdMjesta(parseInt(idMjesta));
			} else if (idOtoka != null) {
				slika = getSlikaByIdOtoka(parseInt(idOtoka));
			} else if (idParka != null) {
				slika = getSlikaByIdParka(parseInt(idParka));
			}

			String contentType = null;
			byte[] data = null;

			if (slika != null && slika.getSadrzaj() != null
					&& slika.getSadrzaj().length > 0) {
				contentType = slika.getTipSadrzaja();
				data = slika.getSadrzaj();
			} else if (noImage != null) {
				contentType = "image/png";
				data = noImage;
			}

			if (data != null) {
				res.setContentType(contentType);

				boolean rescale = false;
				int width = 0;
				int height = -1;
				ImageIcon icon = null;

				// Check if the image needs to be rescaled
				if (req.getParameter("width") != null) {
					width = Math.min(MAX_IMAGE_WIDTH, Integer.parseInt(req
							.getParameter("width")));
					icon = new ImageIcon(data);
					if (width > 0 && width != icon.getIconWidth()) {
						rescale = true;
					}
				}
				if (req.getParameter("height") != null) {
					height = Integer.parseInt(req.getParameter("height"));
				}

				// Rescale the image if required
				if (rescale) {
					final double ratio = (double) width / icon.getIconWidth();
					height = height == -1 ? (int) (icon.getIconHeight() * ratio)
							: height;

					final int imageType = "image/png".equals(contentType) ? BufferedImage.TYPE_INT_ARGB
							: BufferedImage.TYPE_INT_RGB;
					final BufferedImage bImg = new BufferedImage(width, height,
							imageType);
					final Graphics2D g2d = bImg.createGraphics();
					g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
							RenderingHints.VALUE_INTERPOLATION_BICUBIC);
					g2d.drawImage(icon.getImage(), 0, 0, width, height, null);
					g2d.dispose();

					String formatName = "";
					if ("image/png".equals(contentType)) {
						formatName = "png";
					} else if ("image/jpeg".equals(contentType)) {
						formatName = "jpeg";
					} else if ("image/gif".equals(contentType)) {
						formatName = "gif";
					}

					ImageIO.write(bImg, formatName, outputStream);
				} else {
					outputStream.write(data);
				}
			}
		} catch (final NoClassDefFoundError e) {
		}

		outputStream.flush();
		outputStream.close();
	}

	private Slika getSlika(final Integer idSlike) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idSlike_" + idSlike);
		if (s == null) {
			s = slikaDAO.find(idSlike);
			if (s != null) {
				putInCache("idSlike_" + idSlike, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdObjekta(final Integer idObjekta) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idObjekta_" + idObjekta);
		if (s == null) {
			s = slikaDAO.findByIdObjektaP(idObjekta);
			if (s != null) {
				putInCache("idObjekta_" + idObjekta, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdMjesta(final Integer idMjesta) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idMjesta_" + idMjesta);
		if (s == null) {
			s = slikaDAO.findByIdMjestaP(idMjesta);
			if (s != null) {
				putInCache("idMjesta_" + idMjesta, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdOtoka(final Integer idOtoka) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idOtoka_" + idOtoka);
		if (s == null) {
			s = slikaDAO.findByIdOtokaP(idOtoka);
			if (s != null) {
				putInCache("idOtoka_" + idOtoka, s);
			}
		}
		return s;
	}

	private Slika getSlikaByIdParka(final Integer idParka) {
		final SlikaDAO slikaDAO = (SlikaDAO) Component.getInstance("slikaDAO");
		Slika s = getFromCache("idParka_" + idParka);
		if (s == null) {
			s = slikaDAO.findByIdParkaP(idParka);
			if (s != null) {
				putInCache("idParka_" + idParka, s);
			}
		}
		return s;
	}

	@SuppressWarnings("unchecked")
	private Slika getFromCache(final String name) {
		final CacheProvider cacheProvider = (CacheProvider) Component
				.getInstance("org.jboss.seam.cache.cacheProvider");
		Slika s = null;

		s = (Slika) cacheProvider.get("slike", name);

		return s;
	}

	@SuppressWarnings("unchecked")
	private void putInCache(final String name, final Slika value) {
		final CacheProvider cacheProvider = (CacheProvider) Component
				.getInstance("org.jboss.seam.cache.cacheProvider");

		cacheProvider.put("slike", name, value);

	}

}
